﻿using System.Reflection;
using System.Reflection.Emit;
using System.Text.Json;
using rpc_service.cache;

namespace rpc_service.core.support.assembly.il;

public class ILGenerateReturn : ILStep
{
    /// <summary>
    /// 处理方法的返回值生成
    /// </summary>
    /// <param name="il">IL生成器</param>
    /// <param name="result">存储结果的局部变量</param>
    /// <param name="returnType">返回类型</param>
    public void Process(ILGenerator il, LocalBuilder result, Type type, MethodInfo targetMethod)
    {
        Type returnType = targetMethod.ReturnType;
        // 创建实际返回值的局部变量
        LocalBuilder actualResult = il.DeclareLocal(returnType);
        
        if (isPrimitiveType(returnType))
        {
            emitValueForType(il, returnType, result, actualResult);
        }
        else
        {
            // 处理复杂类型，使用 JSON 反序列化
            il.Emit(OpCodes.Ldloc, result);
            il.Emit(OpCodes.Newobj, "JsonSerializerOptions".GetTypeByStr().GetConstructor(Type.EmptyTypes)!);
            
            // 设置 JsonSerializerOptions 属性
            il.Emit(OpCodes.Dup); // 复制 JsonSerializerOptions 实例
            il.Emit(OpCodes.Ldc_I4_1); // true
            il.Emit(OpCodes.Callvirt, "JsonSerializerOptions".GetTypeByStr().GetProperty("PropertyNameCaseInsensitive")!.SetMethod!);
            
            // 调用 JsonSerializer.Deserialize<T>
            var deserializeMethod = "JsonSerializer".GetTypeByStr()
                .GetMethod("Deserialize", new[] { "string".GetTypeByStr(), "JsonSerializerOptions".GetTypeByStr() })
                ?.MakeGenericMethod(returnType)!;
            
            il.Emit(OpCodes.Call, deserializeMethod);
            il.Emit(OpCodes.Stloc, actualResult);
        }

        il.Emit(OpCodes.Ldloc, actualResult);
        il.Emit(OpCodes.Ret);
    }

    /// <summary>
    /// 判断是否为基本类型
    /// </summary>
    /// <param name="type">要检查的类型</param>
    /// <returns>如果是基本类型返回true，否则返回false</returns>
    private bool isPrimitiveType(Type type)
    {
        return type == "int".GetTypeByStr() || type == "string".GetTypeByStr() || 
               type == "bool".GetTypeByStr() || type == "double".GetTypeByStr();
    }

    /// <summary>
    /// 为指定类型生成对应的值
    /// </summary>
    /// <param name="il">IL生成器</param>
    /// <param name="type">要生成值的类型</param>
    private void emitValueForType(ILGenerator il, Type type, LocalBuilder result, LocalBuilder actualResult)
    {
        if (type == typeof(int))
        {
            // Convert.ToInt32(result)
            il.Emit(OpCodes.Ldloc, result);
            il.Emit(OpCodes.Call, typeof(Convert).GetMethod("ToInt32", new Type[] { typeof(string) }));
            il.Emit(OpCodes.Stloc, actualResult);
        }
        else if (type == typeof(string))
        {
            // 直接使用字符串
            il.Emit(OpCodes.Ldloc, result);
            il.Emit(OpCodes.Stloc, actualResult);
        }
        else if (type == typeof(bool))
        {
            // Convert.ToBoolean(result)
            il.Emit(OpCodes.Ldloc, result);
            il.Emit(OpCodes.Call, typeof(Convert).GetMethod("ToBoolean", new Type[] { typeof(string) }));
            il.Emit(OpCodes.Stloc, actualResult);
        }
        else if (type == typeof(double))
        {
            // Convert.ToDouble(result)
            il.Emit(OpCodes.Ldloc, result);
            il.Emit(OpCodes.Call, typeof(Convert).GetMethod("ToDouble", new Type[] { typeof(string) }));
            il.Emit(OpCodes.Stloc, actualResult);
        }
        else
        {
            il.Emit(OpCodes.Ldnull);  // 加载null
        }
    }
}